package com.ljm.shiro.conf;

import com.ljm.common.util.StringUtil;
import com.ljm.shiro.cookie.LjmSimpleCookie;
import com.ljm.shiro.core.ShiroRealm;
import com.ljm.shiro.filter.ShiroFormAuthenticationFilter;
import com.ljm.shiro.session.MyWebSessionManager;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 版权：    Copyright by ljm
 * 描述：
 * 修改人：  HuamingChen
 * 修改时间：2018/12/11
 * 跟踪单号：
 * 修改单号：
 * 修改内容：
 */
@Configuration
@ConditionalOnClass(AuthorizingRealm.class)
@EnableConfigurationProperties(ShiroProperties.class)
public class AutoShiroConfig {
    private final ShiroProperties shiroProperties;

    public AutoShiroConfig(ShiroProperties shiroProperties) {
        this.shiroProperties = shiroProperties;
    }

    /**
     * 自定义的Realm
     */
    @Bean
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealm;
    }

    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(shiroRealm());
        securityManager.setSessionManager(defaultWebSessionManager());
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap());
        shiroFilterFactoryBean.setUnauthorizedUrl(shiroProperties.getUnauthorizedUrl());
        shiroFilterFactoryBean.setLoginUrl(shiroProperties.getLoginUrl());
        shiroFilterFactoryBean.setSuccessUrl(shiroProperties.getSuccessUrl());
        Map<String, Filter> filtersMap = new LinkedHashMap<>();
        filtersMap.put("authc", new ShiroFormAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 凭证匹配器
     *
     * @return 密码校验
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName(shiroProperties.getCredentialsMatcher().getMatcherName());
        hashedCredentialsMatcher.setHashIterations(shiroProperties.getCredentialsMatcher().getIterations());
        return hashedCredentialsMatcher;
    }

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        /*
          setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
          在@Controller注解的类的方法中加入@RequiresRole注解，会导致该方法无法映射请求，导致返回404。
          加入这项配置能解决这个bug
         */
        creator.setUsePrefix(true);
        return creator;
    }

    /**
     * 这里统一做鉴权，即判断哪些请求路径需要用户登录，哪些请求路径不需要用户登录。
     * 这里只做鉴权，不做权限控制，因为权限用注解来做。
     */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();
        List<String> anonUrl = shiroProperties.getAnonUrl();
        //匿名访问
        if (anonUrl != null && !anonUrl.isEmpty()) {
            for (String url : anonUrl) {
                chain.addPathDefinition(url, "anon");
            }
        }
        // 外接系统接口
        List<String> outJoinSysUrl=shiroProperties.getOutJoinSysUrl();
        if(!CollectionUtils.isEmpty(outJoinSysUrl)){
            outJoinSysUrl.forEach(outUrl->{
                chain.addPathDefinition(outUrl, "anon");
            });
        }

        chain.addPathDefinition("/logout", "logout");
        //除了以上的请求外，其它请求都需要登录
        chain.addPathDefinition("/**", "authc");
        return chain;
    }

    @Bean
    public LjmSimpleCookie getSessionIdCookie() {
        LjmSimpleCookie simpleCookie = new LjmSimpleCookie(shiroProperties.getCookie().getName());
        if (!StringUtil.isEmpty(shiroProperties.getCookie().getDomain())) {
            simpleCookie.setDomain(shiroProperties.getCookie().getDomain());
        }
        if (!StringUtil.isEmpty(shiroProperties.getCookie().getMaxAge())) {
            simpleCookie.setMaxAge(shiroProperties.getCookie().getMaxAge());
        }
        if (!StringUtil.isEmpty(shiroProperties.getCookie().getPath())) {
            simpleCookie.setPath(shiroProperties.getCookie().getPath());
        }
        simpleCookie.setHttpOnly(shiroProperties.getCookie().isHttpOnly());
        return simpleCookie;
    }

   /* @Bean
    public RedisSessionDao getRedisSessionDao() {//缓存dao
        return new RedisSessionDao(shiroProperties.getSession().getSessionExpireTime(), redisTemplate);
    }*/

  /* @Bean
   public MemorySessionDAO getMemorySessionDAO(){//内存dao
       MemorySessionDAO sessionDAO=new MemorySessionDAO();
       sessionDAO.setSessionIdGenerator(this.getSessionIdGenerator());
       return sessionDAO;
   }

   @Bean
   @Primary
    public SessionIdGenerator getSessionIdGenerator(){//自定义sessionId策略
        return new RandomSessionIdGenerator();
    }*/


    @Bean
    public MyWebSessionManager defaultWebSessionManager() {
        MyWebSessionManager sessionManager = new MyWebSessionManager();
       // sessionManager.setCacheManager(cacheManager());
        sessionManager.setGlobalSessionTimeout(shiroProperties.getSession().getSessionExpireTime()); //2小时
        sessionManager.setDeleteInvalidSessions(true);
        //关键在这里
        //sessionManager.setSessionDAO(getRedisSessionDao());
        //sessionManager.setSessionDAO(this.getMemorySessionDAO());
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionIdCookie(getSessionIdCookie());
        return sessionManager;
    }

   /* @Bean("shiroCacheManager")
    public RedisCacheManager cacheManager() {
        return new RedisCacheManager(shiroProperties.getSession().getAuthExpireTime());
    }*/
}
